/*  ---- Day 2, TASK 1 -----
 *  Learning goals:
 *    - Setting up low level interrupts
 *	  - The sei() command
 *    - Example usage of an ISR-function
 */

#include <avr/io.h>
//Include this header-file to use interrupts on AVR
#include <avr/interrupt.h>

//Define the ports on the ATMega1284p

#define LED_PORT PORTB
#define LED_DDR  DDRB

#define SWITCH_PORT PORTB
#define SWITCH_DDR  DDRB
#define SWITCH_PIN  PINB

#define SW0  0
#define SW1  1

#define LED0 0
#define LED1 3
#define LED2 1
#define LED3 2

#define ON 1
#define OFF 0


void led_on (uint8_t led);       // Turn on the led
void led_off(uint8_t led);       // Turn off the led
char read_led(uint8_t led);		//Read if led is on/off
char read_switch (uint8_t sw);	//Read switch value


int main(void){
	
	//Set the leds as outputs.  0 = input, 1 = output
	LED_DDR |= (1 << LED1) | (1 << LED3);

	//Enable pullups on the switches
	SWITCH_PORT |= (1 << SW0) | (1 << SW1);
	
	//Set pin-change-interrupt to trigger on negative edge
	PCICR |= (1<< PCIE1);
	
	//Enable interrupts on both switch- pins 
	PCMSK1 |= (1<<PCINT8) | (1<<PCINT9);
	
	//Inital value: LEDs OFF
	LED_PORT = (1<<LED1) | (1<<LED3);



	//Enable global interrupts
	sei();

	/* sei() enables all interrupts globally,
	 * can use cli() to disable interrups globally.
	*/

	//Infinite running loop
	for(;;){
		//Do nothing, all the pin-toggling is happening in the interrupt
	}
}

/*
 *	This is the standard way of defining an interrupt with AVR-GCC;
 *	ISR defines an interrupt (similar to a function in C), however, the
 *	interrupt only gets called when the interrupts happen. In this
 *	example, the interrupt routine (as stated in many textbooks) gets
 *	called every time a pin changes on PORTD and PORTR.
*/

void led_on (uint8_t led){
	// write the LED_PORT register to set the led
	// How can you do this without affecting the other leds?
	// remeber that the led is on when the output is 0/GND!
	LED_PORT &= ~(1 << led); // 0 = ON

}
void led_off(uint8_t led){
	// write the LED_PORT register to clear the led
	LED_PORT |= (1<< led); // 1 = OFF
}

char read_switch (uint8_t sw){
	// read the state of the switch and return it.
	// how can you read the state of only one switch without being disturbed by the others?
	// remember that when the switch is pressed, the input is 0

	if (!(SWITCH_PIN & (1 << sw))){
		return ON;
	} else {
		return OFF;
	}

}

char read_led(uint8_t led) {
	if (LED_PORT & (1 << led)) {
		return OFF; //1 betyr av, 0 betyr paa
	} else {
		return ON;
	}
}

//Interrupt vector for PORTB
ISR(PCINT1_vect){
	if (read_switch(SW0)) {
		if (read_led(LED3)) { //Leser om led er av/paa
			led_off(LED3);
		} else {
			led_on(LED3);
		}
	}
	
	if (read_switch(SW1)) {
		if (read_led(LED1)) { //Leser om led er av/paa
			led_off(LED1);
		} else {
		led_on(LED1);
		}
	}
}

